#ifndef __M_LOOPER_H__
#define __M_LOOPER_H__

/*
    异步工作器类
        1.终止异步工作器
        2.添加数据至缓冲区中
        3.创建线程、交换缓冲区、处理数据（私有操作）
*/

#include "buffer.hpp"
#include <condition_variable>
#include <thread>
#include <mutex>
#include <atomic>
#include <functional>

#include <unistd.h>

namespace Yohifo
{
    using func_t = std::function<void(Buffer &)>;

    enum class AsyncType
    {
        ASYNC_SAFE,
        ASYNC_UNSAFE
    };

    class AsyncLooper
    {
    public:
        using ptr = std::shared_ptr<AsyncLooper>;

    public:
        AsyncLooper(const func_t &callBack, const AsyncType &type)
            : _stop(false), _thread(std::thread(&AsyncLooper::ThreadHandler, this)), _call_back(callBack), _type(type)
        {
        }

        ~AsyncLooper()
        {
            Stop();
        }

        void Stop()
        {
            // 停止标志位置为 true
            _stop = true;

            // 唤醒消费者，将剩余的数据赶紧消费完
            _com_cond.notify_all();

            // // 等待异步线程退出
            _thread.join();
        }

        // 生产数据
        void Push(const char *data, size_t len)
        {
            if (!_stop)
            {
                // 加锁保护
                std::unique_lock<std::mutex> lock(_mtx);

                // 等待生产缓冲区中大小足够（安全情况下）
                if (_type == AsyncType::ASYNC_SAFE)
                    _pro_cond.wait(lock,
                                   [&]()
                                   {
                                       return (_pro_buff.WriteableSize() >= len);
                                   });

                // 生产数据
                _pro_buff.Push(data, len);
            }

            // 唤醒消费者，处理数据
            _com_cond.notify_one();
        }

    private:
        // 消费数据
        void ThreadHandler()
        {
            while (true)
            {
                // sleep(1);

                // 加锁保护（保护等待数据的过程）
                {
                    std::unique_lock<std::mutex> lock(_mtx);

                    if (_stop && _pro_buff.Empty())
                        break;

                    // 等生产缓冲区中有数据，或者 _stop 为 true
                    _com_cond.wait(lock,
                                   [&]()
                                   {
                                       return (!_pro_buff.Empty() || _stop);
                                   });

                    // 交换缓冲区
                    _com_buff.Swap(_pro_buff);

                    // 唤醒生产者（安全情况下）
                    if (_type == AsyncType::ASYNC_SAFE)
                        _pro_cond.notify_all();
                }

                // 调用异步线程，进行任务处理
                _call_back(_com_buff);

                // 清空处理缓冲区
                _com_buff.InitBuffer();
            }
        }

    private:
        Buffer _pro_buff;                  // 生产缓冲区（任务写入）
        Buffer _com_buff;                  // 消费缓冲区（任务处理）
        std::condition_variable _pro_cond; // 生产条件变量
        std::condition_variable _com_cond; // 消费条件变量
        std::mutex _mtx;                   // 互斥锁

        // 细节：次线程需要依赖缓冲区资源，因此必须后创建
    private:
        std::atomic<bool> _stop; // 异步工作器终止标识
        func_t _call_back;       // 回调函数
        std::thread _thread;     // 任务处理线程
        AsyncType _type;         // 是否安全（扩容 / 阻塞）
    };
}

#endif